﻿using DapperORM.Abstractions;
using DapperORM.Abstractions.Adapter;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Threading.Tasks;

namespace DapperORM.BulkSqlserver
{
    /// <summary>
    /// MSSQL
    /// </summary>
    public class SqlServerBulk : IBulk
    {
        public async Task BulkInsetAsync<TEntity>(IDbConnection connection, IEnumerable<TEntity> entities, IDbTransaction transaction = null, int? commandTimeout = null) where TEntity : class
        {
            if (!(connection is SqlConnection sqlConnection))
                throw new InvalidOperationException($"{nameof(connection)} is not SqlConnection");
            if (sqlConnection.State != ConnectionState.Open)
                await sqlConnection.OpenAsync();
            var type = typeof(TEntity);
            var columns = SqlMapperEx.KeyPropertiesCache(type).Where(m => m.KeyType != KeyType.Identity).ToList();
            var sqlTran = transaction == null ? null : transaction as SqlTransaction;
            var sqlBulkCopy = new SqlBulkCopy(sqlConnection, SqlBulkCopyOptions.KeepIdentity, sqlTran);
            try
            {
                sqlBulkCopy.DestinationTableName = SqlMapperEx.GetTableName(type);
                sqlBulkCopy.BatchSize = 10000;
                if (commandTimeout.HasValue && commandTimeout.Value > 0)
                    sqlBulkCopy.BulkCopyTimeout = commandTimeout.Value;
                foreach (var item in columns)
                {
                    sqlBulkCopy.ColumnMappings.Add(item.ColumnName, item.ColumnName);
                }

                var dataTable = entities.ToDataTable(columns);
                await sqlBulkCopy.WriteToServerAsync(dataTable);
            }
            finally
            {
                sqlBulkCopy.Close();
            }
        }
    }
}
